package com.slipper.groovy.util;

import com.alibaba.excel.EasyExcel;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.slipper.PaasContext;
import com.slipper.constants.Constants;
import com.slipper.core.excel.ColumnWidthStrategy;
import com.slipper.core.excel.DateTimeDateConverter;
import com.slipper.core.excel.ExcelReadListener;
import com.slipper.core.file.FileServiceUtil;
import com.slipper.core.poi.excel.ExcelConfig;
import com.slipper.core.poi.excel.ExcelEngine;
import com.slipper.exception.CommonException;
import com.slipper.system.affix.bo.AffixItemBO;
import com.slipper.system.affix.service.AffixItemService;
import com.slipper.system.codeless.bo.TemplateBO;
import com.slipper.system.codeless.service.TemplateService;
import com.slipper.util.FileUtil;
import com.slipper.util.Tool;
import jakarta.servlet.http.HttpServletResponse;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;

public final class OfficeUtil {
    /**
     * 数据导出
     * @param fileName 导出文件名
     * @param headList 表头
     * @param widthList 表头宽度
     * @param dataList 数据
     */
    public static void exportExcel(
            String fileName,
            List<String> headList,
            List<Integer> widthList,
            List<Map<String, Object>> dataList) throws IOException {
        HttpServletResponse response = Constants.getCurrentResponse();
        response.setHeader("Access-Control-Allow-Headers", "Content-Disposition");
        String trueName = URLEncoder.encode(fileName, StandardCharsets.UTF_8);
        response.setHeader("Content-Disposition", "attachment; filename=\"" + trueName + "\"");
        response.setContentType("application/octet-stream");

        List<List<Object>> writeList = new ArrayList<>();
        dataList.forEach(data -> {
            List<Object> row = new ArrayList<>();
            for (String s : headList) {
                row.add(data.get(s));
            }
            writeList.add(row);
        });

        EasyExcel.write(response.getOutputStream())
                .head(headList.stream().map(Collections::singletonList).toList())
                .registerConverter(new DateTimeDateConverter())
                .registerWriteHandler(new ColumnWidthStrategy(widthList))
                .sheet("Sheet0")
                .doWrite(writeList);
    }

    /**
     * 根据模板导出excel
     * @param code 模板编码
     * @param data 数据，
     *         key为标签名，
     *             当value为对应的值非list时，value为标签值，
     *             当value为对应的值list，
     *        当key为mergeList的key时为单元格合并，
     *             value为List<String[]>，String[] {
     *                  startCellRowIndex, // 合并开始cell的行号，从0开始
     *                  endCellRowIndex, // 合并结束cell的行号，从0开始
     *                  startCellColIndex,  // 合并开始cell的列号，从0开始
     *                  endCellColIndex } // 合结束始cell的行号，从0开始
     */
    public static void exportExcel(String code, Map<String, Object> data, String fileName) throws Exception {
        if (Tool.isBlank(code)) return;

        TemplateBO templateBO = PaasContext.getBean(TemplateService.class).queryBy(code);
        if (templateBO == null || Tool.isBlank(templateBO.getFileId())) return;

        AffixItemBO affixItem = PaasContext.getBean(AffixItemService.class).queryBy(templateBO.getFileId());
        if (affixItem == null) return;

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        InputStream inputStream = new ByteArrayInputStream(FileServiceUtil.readFile(affixItem.getSavePath()));
        ExcelEngine engine = new ExcelEngine(new ExcelConfig(inputStream));
        engine.render(data);
        engine.write(outputStream);
        engine.close();
        FileUtil.download(Constants.getCurrentResponse(), fileName, outputStream.toByteArray());
        outputStream.close();
    }

    /**
     * 根据模板导出word
     * @param code 模板编码
     * @param data 数据，详见 <a href="http://deepoove.com/poi-tl/">...</a>
     */
    public static void exportWord(String code, Map<String, Object> data, String fileName) throws Exception {
        if (Tool.isBlank(code)) throw new CommonException("模板编码不能为空！");

        TemplateBO templateBO = PaasContext.getBean(TemplateService.class).queryBy(code);
        if (templateBO == null || Tool.isBlank(templateBO.getFileId())) throw new CommonException("模板编码不存在！");

        AffixItemBO affixItem = PaasContext.getBean(AffixItemService.class).queryBy(templateBO.getFileId());
        if (affixItem == null) throw new CommonException("模板编码附件不存在！");

        LoopRowTableRenderPolicy policy = null;
        ConfigureBuilder builder = null;
        for (Map.Entry<String, Object> entry : data.entrySet()){
            if (entry.getValue() instanceof Collection<?>) {
                if (builder == null) {
                    builder = Configure.builder();
                }
                if (policy == null) {
                    policy = new LoopRowTableRenderPolicy();
                }
                builder.bind(entry.getKey(), policy);
            }
        }

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        InputStream inputStream = new ByteArrayInputStream(FileServiceUtil.readFile(affixItem.getSavePath()));
        XWPFTemplate template;
        if (builder != null) {
            template = XWPFTemplate.compile(inputStream, builder.build());
        } else {
            template = XWPFTemplate.compile(inputStream);
        }
        template.render(data);
        template.write(outputStream);
        template.close();
        FileUtil.download(Constants.getCurrentResponse(), fileName, outputStream.toByteArray());
        outputStream.close();
    }

    /**
     * 解释word模板并返回InputStream
     * @param code 模板编码
     * @param data 数据，详见 <a href="http://deepoove.com/poi-tl/">...</a>
     */
    public static InputStream wordToInputStream(String code, Map<String, Object> data) throws Exception {
        if (Tool.isBlank(code)) throw new CommonException("模板编码不能为空！");

        TemplateBO templateBO = PaasContext.getBean(TemplateService.class).queryBy(code);
        if (templateBO == null || Tool.isBlank(templateBO.getFileId())) throw new CommonException("模板编码不存在！");

        AffixItemBO affixItem = PaasContext.getBean(AffixItemService.class).queryBy(templateBO.getFileId());
        if (affixItem == null) throw new CommonException("模板编码附件不存在！");

        LoopRowTableRenderPolicy policy = null;
        ConfigureBuilder builder = null;
        for (Map.Entry<String, Object> entry : data.entrySet()){
            if (entry.getValue() instanceof Collection<?>) {
                if (builder == null) {
                    builder = Configure.builder();
                }
                if (policy == null) {
                    policy = new LoopRowTableRenderPolicy();
                }
                builder.bind(entry.getKey(), policy);
            }
        }

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        InputStream inputStream = new ByteArrayInputStream(FileServiceUtil.readFile(affixItem.getSavePath()));
        XWPFTemplate template;
        if (builder != null) {
            template = XWPFTemplate.compile(inputStream, builder.build());
        } else {
            template = XWPFTemplate.compile(inputStream);
        }
        template.render(data);
        template.write(outputStream);
        template.close();
        InputStream resultInputStream = new ByteArrayInputStream(outputStream.toByteArray());
        outputStream.close();
        return resultInputStream;
    }

    /**
     * 解释word模板并返回InputStream
     * @param file 文件路径
     * @param data 数据，详见 <a href="http://deepoove.com/poi-tl/">...</a>
     */
    public static InputStream wordToInputStream(File file, Map<String, Object> data) throws Exception {
        LoopRowTableRenderPolicy policy = null;
        ConfigureBuilder builder = null;
        for (Map.Entry<String, Object> entry : data.entrySet()){
            if (entry.getValue() instanceof Collection<?>) {
                if (builder == null) {
                    builder = Configure.builder();
                }
                if (policy == null) {
                    policy = new LoopRowTableRenderPolicy();
                }
                builder.bind(entry.getKey(), policy);
            }
        }

        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        XWPFTemplate template;
        if (builder != null) {
            template = XWPFTemplate.compile(file, builder.build());
        } else {
            template = XWPFTemplate.compile(file);
        }
        template.render(data);
        template.write(outputStream);
        template.close();
        InputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        outputStream.close();
        return inputStream;
    }

    public static List<List<Map<Integer, String>>> read(byte[] bytes) {
        return read(bytes, 0);
    }

    public static List<List<Map<Integer, String>>> read(byte[] bytes, int headRowNumber) {
        ExcelReadListener listener = new ExcelReadListener();
        EasyExcel.read(new ByteArrayInputStream(bytes), listener).sheet().headRowNumber(headRowNumber).doRead();
        return listener.getSheetDataList();
    }

    public static List<Map<Integer, String>> read(byte[] bytes, int sheetIndex, int headRowNumber) {
        ExcelReadListener listener = new ExcelReadListener();
        EasyExcel.read(new ByteArrayInputStream(bytes), listener).sheet(sheetIndex).headRowNumber(headRowNumber).doRead();
        return !listener.getSheetDataList().isEmpty() ? listener.getSheetDataList().getFirst() : Collections.emptyList();
    }
}
